﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace Pacman
{
     abstract class Mouvement
    {
        private Fantome fantome;

        protected byte[,] map;

        // Gestion de la vitesse
        protected int indDividVitesse; // 0 (normal) ou 1 (ralenti)
        protected static int[] tDividVitesse = { 10, 20 };
        protected static Vector2 vHaut = new Vector2(0, -20);
        protected static Vector2 vDroite = new Vector2(20, 0);
        protected static Vector2 vBas = new Vector2(0, 20);
        protected static Vector2 vGauche = new Vector2(-20, 0);
        
        // Gestion du tunnel
        protected const float Y = 14 * 20;
        protected const float XFinGauche = 1 * 20;
        protected const float XFinDroite = 26 * 20;
        protected const float XDebGauche = 5 * 20;
        protected const float XDebDroite = 22 * 20;


        
        /// 
        /// Constructeurs
        ///

        public Mouvement(byte[,] _map)
        {
            map = _map;
        }

        public Mouvement(Fantome _fantome, byte[,] _map)
        {
            map = _map;
            this.fantome = _fantome;
            indDividVitesse = 0;
        }

        public Mouvement(Fantome _fantome, byte[,] _map, int _indDividVitesse)
        {
            map = _map;
            this.fantome = _fantome;
            indDividVitesse = _indDividVitesse;
        }

        /// 
        /// Fonctions
        /// 

        public abstract void Move(Jeu jeu, Sommet[,] mesSommets, Vector2 Destination, Fantome fantome);

        /// <summary>
        /// Avance le fantome selon la vitesse
        /// </summary>
        /// <param name="fantome">fantome à avancer</param>
        /// <returns> true si entre 2 cases, false sinon</returns>
        public void Avance(Jeu jeu, Sommet[,] mesSommets, Pacman pacman, Fantome fantome)
        {
            MouvementDijkstra monMouv = new MouvementDijkstra(fantome,map); //Utilisé pour le mouvement de sortie

            //Si on est en train d'avancer entre deux cases
            if (fantome.Position.X % 20 != 0 || fantome.Position.Y % 20 != 0)
            {
                fantome.Position = fantome.Position + fantome.Vitesse / tDividVitesse[indDividVitesse];
                return;
            }

            // Gestion du tunnel
            if (fantome.Position.Y == Y && (fantome.Position.X >= XDebDroite || fantome.Position.X <= XDebGauche))
            {
                if ((fantome.Position.X == XDebGauche && fantome.Vitesse == vGauche) ||
                    (fantome.Position.X == XDebDroite && fantome.Vitesse == vDroite)) // entree tunnel
                    changerVitesse(true);
                else if ((fantome.Position.X == XDebGauche && fantome.Vitesse == vDroite) ||  // sortie tunnel
                    (fantome.Position.X == XDebDroite && fantome.Vitesse == vGauche))
                {
                    if (!(fantome.Mvt is MouvementFuite))
                    {
                        changerVitesse(false);
                        fantome.AncienMouvement();
                    }
                }
                else if (fantome.Position.X == XFinDroite && fantome.Vitesse == vDroite) //fin du tunnel Droit
                {
                    fantome.Position = new Vector2(XFinGauche, Y);
                    return;
                }
                else if (fantome.Position.X == XFinGauche && fantome.Vitesse == vGauche)  //fin du tunnel gauche
                {
                    fantome.Position = new Vector2(XFinDroite, Y);
                    return;
                }
            }

            // Gestion du mouvement du fantome
            if (this != null && !(this is MouvementFuite))
            {
                Vector2 vectTest = fantome.Position;

                //Si le fantome voit le pacman il passe en Dijkstra
                if (fantome.Position.X == pacman.Position.X) //Si ils sont sur la même colonne 
                {
                    if (fantome.Position.Y < pacman.Position.Y)//Si le fantome est plus haut
                    {
                        //On cherche vers le bas
                        while (BasPossible(vectTest) && PixToMap(vectTest) != PixToMap(pacman.Position))
                        {
                            vectTest = vectTest + new Vector2(0, 20);
                        }
                    }
                    else //Si le pacman est plus haut
                    {
                        //On cherche vers le haut
                        while (HautPossible(vectTest) && PixToMap(vectTest) != PixToMap(pacman.Position))
                        {
                            vectTest = vectTest + new Vector2(0, -20);
                        }
                    }
                } //fin  if (fantome.Position.X == pacman.Position.X)
                else if (fantome.Position.Y == pacman.Position.Y) //Si ils sont sur la même ligne
                {
                    if (fantome.Position.X < pacman.Position.X)//Si le fantome est à gauche
                    {
                        while (DroitePossible(vectTest) && PixToMap(vectTest) != PixToMap(pacman.Position)) //On cherche vers la droite
                        {
                            vectTest = vectTest + new Vector2(20, 0);
                        }
                    }
                    else //Si le pacman est à gauche
                    {
                        //On cherche vers la gauche
                        while (GauchePossible(vectTest) && PixToMap(vectTest) != PixToMap(pacman.Position))
                        {
                            vectTest = vectTest + new Vector2(-20, 0);
                        }
                    }
                } // fin  if (fantome.Position.Y == pacman.Position.Y)


                //On test maintenant si on a rencontré un mur ou pas dans le chemin
                if (PixToMap(vectTest) == PixToMap(pacman.Position))//Ici on n'a rencontré aucun mur
                {
                    fantome.Mvt = new MouvementDijkstra(fantome, jeu.Map, indDividVitesse);
                }
            } //if (fantome.Mvt != null)


            if (fantome.Exit && (fantome.Couleur == "Rose" || fantome.Couleur == "Bleu"))
                    monMouv.Move(jeu, mesSommets, Fantome.SORTIEGAUCHE_G, fantome);
            else if (fantome.Exit && (fantome.Couleur == "Rouge" || fantome.Couleur == "Vert"))
                    monMouv.Move(jeu, mesSommets, Fantome.SORTIEDROITE_G, fantome);
            else
                this.Move(jeu, mesSommets, pacman.Position, fantome);


            fantome.Position = fantome.Position + fantome.Vitesse / tDividVitesse[indDividVitesse];
        }//Avance()

        public void changerVitesse(bool isSlow)
        {
            if (!isSlow) // Pb de décalage d'un pixel possible lors de l'accelerations
            {
                float rectificationX = fantome.Position.X % 2;
                float rectificationY = fantome.Position.Y % 2;
                Vector2 Position = fantome.Position;
                // Modification
                if (fantome.Vitesse == vGauche)
                    Position.X -= rectificationX;
                else if (fantome.Vitesse == vDroite)
                    Position.X += rectificationX;
                if (fantome.Vitesse == vHaut)
                    Position.Y -= rectificationY;
                else if (fantome.Vitesse == vBas)
                    Position.Y += rectificationY;
                // Application
                fantome.Position = Position;
                IndDividVitesse = 0;
            }
            else
                IndDividVitesse = 1;
        }


        ///
        /// Outils
        /// 

        /// <summary>
        /// Retourne les cases possibles autour de la texture
        /// </summary>
        /// <returns>bool[] dans lequel les indices 0=>Haut, 1=>Droite, 2=>Bas, 3=>Gauche</returns>
        protected bool[] getCasesPossibles()
        {
            bool[] result = new bool[4];
            if (HautPossible(fantome.Position, true))
                result[0] = true;
            if (DroitePossible(fantome.Position, true))
                result[1] = true;
            if (BasPossible(fantome.Position, true))
                result[2] = true;
            if (GauchePossible(fantome.Position, true))
                result[3] = true;

            return result;
        }


        //On donne le vecteur en PIX 
        public bool HautPossible(Vector2 _v, bool isNotPrecedent = false)
        {
            if (isNotPrecedent && fantome != null && fantome.Position - fantome.Vitesse == fantome.Position + new Vector2(0, -20))
                return false;
            int x = (int)_v.X / 20; int y = (int)_v.Y / 20;
            if (map[y - 1, x] != 0 && (map[y - 1, x] != 4 || fantome.Exit))
                return true;
            else
                return false;
        }

        public bool BasPossible(Vector2 _v, bool isNotPrecedent = false)
        {
            if (isNotPrecedent && fantome != null && fantome.Position - fantome.Vitesse == fantome.Position + new Vector2(0, 20))
                return false;
            int x = (int)_v.X / 20; int y = (int)_v.Y / 20;
            if (map[y + 1, x] != 0 && (map[y + 1, x] != 4 || fantome.Exit))
                return true;
            else
                return false;
        }

        public bool GauchePossible(Vector2 _v, bool isNotPrecedent = false)
        {
            if (isNotPrecedent && fantome != null && fantome.Position - fantome.Vitesse == fantome.Position + new Vector2(-20, 0))
                return false;
            int x = (int)_v.X / 20; int y = (int)_v.Y / 20;
            if (map[y, x - 1] != 0 && (map[y, x - 1] != 4 || fantome.Exit))
                return true;
            else
                return false;
        }

        public bool DroitePossible(Vector2 _v, bool isNotPrecedent = false)
        {
            if (isNotPrecedent && fantome != null && fantome.Position - fantome.Vitesse == fantome.Position + new Vector2(20, 0))
                return false;
            int x = (int)_v.X / 20; int y = (int)_v.Y / 20;
            if (map[y, x + 1] != 0 && (map[y, x + 1] != 4 || fantome.Exit))
                return true;
            else
                return false;
        }



        public Vector2 MapToPix(Vector2 _v)
        {
            return new Vector2(_v.X * 20, _v.Y * 20);
        }

        public Vector2 PixToMap(Vector2 _v)
        {
            return new Vector2(_v.X / 20, _v.Y / 20);
        }

        public Vector2 getCase(Vector2 _v)
        {
            Vector2 result;

            result.X = (int)_v.X / 20;
            result.Y = (int)_v.Y / 20;
            return result;
        }

        ///
        /// Getter / setter
        /// 

        public int IndDividVitesse
        {
            get { return indDividVitesse; }
            set { indDividVitesse = value; }
        }
    }
}
